﻿using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Transactions;
using Newtonsoft.Json;
using T.ServiceComponent.Database.Service;
using T.FAS.Runtime.DataModel.Dao;
using T.FAS.Runtime.Metadata.Entity.DataModel; 
using T.FAS.Runtime.Metadata.Entity;
using T.FAS.Runtime.Base.Entity;
using T.ServiceComponent.Error;

namespace T.FAS.Runtime.DataModel.Dao
{
    public class CompositeDataObjectLogic
    {
        #region Fields & Properties
        public const string MetaDataID = DataModelConst.CDOMetaType;
        public const string MetaDataName = "复合数据对象";

        private readonly CompositeDataObjectELBDao _compositeDataObjectDao = new CompositeDataObjectELBDao();
        private readonly CompositeNodeObjectELBDao _compositeNodeObjectELBDao = new CompositeNodeObjectELBDao();
        private readonly CompositeNodeObjectElementELBDao _elementELBDao = new CompositeNodeObjectElementELBDao();
        private readonly AssociationELBDao _associationELBDao = new AssociationELBDao();
        private readonly AssociateItemELBDao _associateItemELBDao = new AssociateItemELBDao();
        private readonly AssociationRefElementELBDao _associationRefElementELBDao = new AssociationRefElementELBDao();
        private readonly DataObjectELBDao _dataObjectDao = new DataObjectELBDao();
        private readonly DatabaseELBDao _databaseDao = new DatabaseELBDao();

        #endregion

        #region 获取元数据内容

        /// <summary>
        /// 获取元数据内容
        /// </summary>
        /// <param name="metaDataId"></param>
        /// <returns></returns>
        public CompositeDataObject GetCompositeDataObject(string metaDataId)
        {
            if (string.IsNullOrEmpty(metaDataId))
                throw new FasException(DataModelErrorCode.NullValue, $"{MetaDataName}id为空");
            var cdo = _compositeDataObjectDao.GetCompositeDataObject(metaDataId);
            InitializeCDOMetadata(cdo);
            //PackagingDependencyMetaData(cdo);
            return cdo;
        }

        /// <summary>
        /// 获取所有引用指定DO的CNO集合
        /// </summary>
        /// <param name="doId"></param>
        /// <returns></returns>
        public List<CompositeNodeObject> GetCNOByReferSpecificDO(string doId)
        {
            var result = new List<CompositeNodeObject>();
            if (string.IsNullOrEmpty(doId))
            {
                return result;
            }
            var objects = _compositeNodeObjectELBDao.GetCNOByReferSpecificDO(doId);
            if (objects != null)
            {
                objects.ForEach(cno => {
                    cno.Elements = _elementELBDao.GetCompositeNodeObjectElements(cno.ID);
                    result.Add(cno);
                });
            }
            return result;
        }

        public List<CompositeDataObject> GetCompositeDataObjects()
        {
            return _compositeDataObjectDao.GetCompositeDataObjects();
        }

        public List<CompositeDataObject> GetCompositeDataObjectsByCondition(Dictionary<string, object> condition)
        {
            return _compositeDataObjectDao.GetCompositeDataObjectsByCondition(condition);
        }

        public int GetCompositeDataObjectCountByCondition(Dictionary<string, object> condition)
        {
            return _compositeDataObjectDao.GetCompositeDataObjectCountByCondition(condition);
        }

        /// <summary>
        /// 重新组装CDO依赖的元数据信息
        /// </summary>
        /// <param name="cdo"></param>
        /// <returns></returns>
        public CompositeDataObject PackagingDependencyMetaData(CompositeDataObject cdo)
        {

            if (cdo == null)
                return null;
            var unifyCode = DataModelErrorCode.GetUnifiedErrorCode(MetaDataID, cdo.ID, cdo.Code);
            try
            {
                foreach (var cno in cdo.CompositeNodeObjects)
                {
                    if (cno.DataObject == null)
                        cno.DataObject = _dataObjectDao.GetDataObjectByID(cno.DataObjectID);
                    if (cno.DataObject?.Database == null && cno.DataObject != null)
                        cno.DataObject.Database = _databaseDao.GetDatabaseByID(cno.DataObject.DatabaseID);
                    var outerAssos = cno.Associations.Where(o => o.AssociateType == AssociateType.OuterLeftJoin).ToList();
                    var refeles = outerAssos.SelectMany(outer => outer.RefElements).ToList();
                    //初始化Element对应的DataColumn属性
                    if (cno.Elements != null && cno.Elements.Count > 0)
                    {
                        foreach (var ele in cno.Elements)
                        {
                            if (ele.ElementType == ElementType.Normal)   //初始化所有Normal Element对应的DataColumn对象
                            {
                                ele.DataColumn = cno.DataObject.Columns.Find(col => col.ID == ele.DataColumnID);
                                //暂时去掉校验,由Validator统一校验，修复
                                //if (ele.DataColumn == null) 
                                //throw new FasException(DataModelErrorCode.CDO.InitError, $"ErrorCode:{DataModelErrorCode.NeedRepairError},CDO:{cdo.Code}节点CNO:{cno.ID}的元素Element:{ele.ID}对应的DO:{cno.DataObject.Code}对应的列不存在!");
                            }
                            else if (ele.ElementType == ElementType.Reference)  //为Reference类型的Element找到对应的DataColumn
                            {
                                if (outerAssos == null)
                                    throw new FasException(DataModelErrorCode.CDO.InitError, $"{unifyCode}的节点CNO:{cno.ID}中的ele:{ele.ID}类型为Reference，但该CNO节点中不存在外键关联Asso");
                                if (refeles != null && refeles.Count > 0)
                                {
                                    //包含当前Ref Element节点的RefElement
                                    var outerAssoRefele = refeles.Where(o => o.TargetElementID == ele.ID)?.FirstOrDefault();
                                    if (outerAssoRefele == null)
                                        throw new FasException(DataModelErrorCode.CDO.InitError, $"{unifyCode}的节点CNO:{cno.ID}中的ele:{ele.ID}类型为Reference，但未找到对应的外键关联Asso");
                                    var refEleColumn = outerAssoRefele.SourceElementID;
                                    if (refEleColumn == null)
                                        throw new FasException(DataModelErrorCode.CDO.InitError, $"{unifyCode}的节点CNO:{cno.ID}中的ele:{ele.ID}类型为Reference，但未在外键关联Asso中找到对应的DO的列");
                                    var AssoDataObjectID = outerAssos.Find(asso => asso.ID == outerAssoRefele.AssociationID)?.AssoDataObjectID;
                                    if (string.IsNullOrEmpty(AssoDataObjectID))
                                        throw new FasException(DataModelErrorCode.CDO.InitError, $"{unifyCode}的节点CNO:{cno.ID}中的ele:{ele.ID}类型为Reference，但未在外键关联Asso中找到对应的DO.ID");
                                    //CDO不需要处理导入导出的元数据依赖，因为DO导入在CDO之前
                                    var refEleRelatedDataObject = _dataObjectDao.GetDataObjectByID(AssoDataObjectID);
                                    if (refEleRelatedDataObject == null)
                                        throw new FasException(DataModelErrorCode.CDO.InitError, $"{unifyCode}的节点CNO:{cno.ID}中的ele:{ele.ID}类型为Reference，但外键关联Asso中对应的外键关联DO:{AssoDataObjectID}未获取到实例");
                                    var refEleRelatedColumn = refEleRelatedDataObject?.Columns.Find(col => col.ID == refEleColumn);
                                    //暂时去掉校验,由Validator统一校验，修复
                                    //if (refEleRelatedColumn == null)
                                    //    throw new FasException(DataModelErrorCode.CDO.InitError, $"{unifyCode}的节点CNO:{cno.ID}中的ele:{ele.ID}类型为Reference，但外键关联Asso中对应的外键关联DO:{refEleRelatedDataObject.Code}中未获取到ColumnID:{refEleColumn}的列");
                                    ele.DataColumn = refEleRelatedColumn;
                                }
                            }
                            /*
                             * 低代码改动
                             * Description:
                             *      运行时将DataColumn的数据类型|长度|精度|可空 属性映射到CNO.Element属性中，现在对接了运行时缓存，只有第一次Get会比较慢，
                             *      DO改动发布时只清理节点不够，需要将关联的CDO缓存全部清掉。
                             * Tag:
                             *      DataType
                             */
                            if (ele.DataColumn != null)
                            {
                                ele.DataType = DataTypeTool.MappingDataColumnDataTypeToCNOElementDataType(ele.DataColumn);
                                ele.Length = ele.DataColumn.Length;
                                ele.Precision = ele.DataColumn.Precision;
                                ele.IsAllowNull = ele.DataColumn.IsNullable;
                            }
                        }
                    }
                    //cno.ChildCompositeNodeObjects = cdo.CompositeNodeObjects
                    //                                    .Where(o => o.ParentObjectID == cno.ID)
                    //                                    .OrderBy(o => o.ID)
                    //                                    .ToList();
                    //cno.ChildCompositeNodeObjects.ForEach(child => child.ParentObject = cno);
                    //构造关联关系实体引用
                    if (cno.Associations != null && cno.Associations.Count > 0)
                    {
                        foreach (var asso in cno.Associations)
                        {
                            //if (asso.AssociateType == AssociateType.InnerJoin)
                            //{
                            //    asso.AssoDomaiModel = cdo;
                            //    asso.AssoCompositeNodeObject = cdo.CompositeNodeObjects.Find(o => o.ID == asso.AssoCompositeNodeObjectID);
                            //}
                            if (asso.AssociateType == AssociateType.OuterLeftJoin)
                            {
                                asso.AssoDataObject = _dataObjectDao.GetDataObjectByID(asso.AssoDataObjectID);
                            }
                        }
                    }
                }

                /***********低代码改动：增加Get获取Element所属状态机集合的方法*************/
                StateMachineMetadataLogic StateMachineLogic = new StateMachineMetadataLogic();

                var stateMachines = StateMachineLogic.GetStateMachineMetadatas(cdo.ID);
                if (stateMachines != null && stateMachines.Count > 0)
                    foreach (var ele in cdo.RootCompositeNodeObject.Elements)
                    {
                        ele.StateMachines = stateMachines.Where(s => s.CDOColKey == (ele.Alias ?? ele.Name)).ToList();
                    }
                return cdo;
            }
            catch (Exception e)
            {
                throw new FasException(DataModelErrorCode.DQ.InitError, $"{unifyCode}初始化失败，请检查！", e);
            }
        }

        /// <summary>
        /// 初始化CDO元数据本身，从DB中拉取完整CDO元数据，注意不要传null到前端，返回空数组
        /// </summary>
        /// <param name="cdo"></param>
        /// <returns></returns>
        private CompositeDataObject InitializeCDOMetadata(CompositeDataObject cdo)
        {
            if (cdo == null) return null;
            if (cdo.CompositeNodeObjects != null && cdo.CompositeNodeObjects.Count > 0) return cdo;
            var allCnos = _compositeNodeObjectELBDao.GetCompositeNodeObjects(cdo.ID).ToList();
            var allCnoEles = _elementELBDao.GetCompositeNodeObjectElementsByMetaDataForeignKey(cdo.ID).GroupBy(ele => ele.CompositeNodeObjectID);
            var allAsso = _associationELBDao.GetAssociationsByMetaDataForeignKey(cdo.ID).GroupBy(asso => asso.CompositeNodeObjectID);
            var allAssoItems = _associateItemELBDao.GetAssociateItemsByMetaDataForeignKey(cdo.ID).GroupBy(item => item.AssociationID);
            var allAssoRefItems = _associationRefElementELBDao.GetAssociationRefElementsByMetaDataForeignKey(cdo.ID).GroupBy(item => item.AssociationID);
            cdo.CompositeNodeObjects = allCnos;
            foreach (var cno in cdo.CompositeNodeObjects)
            {
                cno.Elements = allCnoEles.FirstOrDefault(e => e.Key == cno.ID).ToList();
                cno.Associations = allAsso.FirstOrDefault(e => e.Key == cno.ID)?.ToList() ?? new List<Association>();
                if (cno.Associations != null && cno.Associations.Count > 0)
                {
                    foreach (var asso in cno.Associations)
                    {
                        asso.Items = allAssoItems.FirstOrDefault(e => e.Key == asso.ID)?.ToList() ?? new List<AssociateItem>();
                        asso.RefElements = allAssoRefItems.FirstOrDefault(e => e.Key == asso.ID)?.ToList() ?? new List<AssociationRefElement>();
                    }
                }
            }
            cdo.BuildModelObjectRelation();
            return cdo;
        }
         
        #endregion

        #region 保存
        /// <summary>
        /// 保存CDO
        /// </summary>
        /// <param name="metaData"></param>
        public void SaveCompositeDataObject(CompositeDataObject cdo)
        {
            var unifyCode = DataModelErrorCode.GetUnifiedErrorCode(MetaDataID, cdo?.ID, cdo?.Code);
            /***********低代码改动：处理CDO各个部分元数据逻辑放到Logic中*************/
            foreach (var cno in cdo.CompositeNodeObjects)
            {
                //CDO不需要处理导入导出的元数据依赖，因为DO导入在CDO之前
                if (ConfigTool.IsDebug(MetaDataID))
                {
                    var cnoRelatedDO = _dataObjectDao.GetDataObjectByID(cno.DataObjectID);
                    if (cnoRelatedDO == null)
                        throw new FasException(DataModelErrorCode.CDO.CreateError, $"{unifyCode}的节点CNO:{cno.ID}对应的DO:{cno.DataObjectID}不存在!");
                }

                /***************此处GUID修改时要保持一致******************/
                #region 处理CNO Element：Element.DataType等，**不再需要处理，改为运行时读取Element对应的DataColumn属性，类型、长度、精度、可空属性指向DataColumn对应属性

                #endregion

                #region 将所有子表的外键赋值完整
                cno.CompositeDataObjectID = cdo.ID;
                EntityTools.FillSystemFiledForAdd(cno, cdo);

                if (cno.Elements != null && cno.Elements.Count > 0)
                {
                    foreach (var ele in cno.Elements)
                    {
                        ele.CompositeDataObjectID = cdo.ID;
                        ele.CompositeNodeObjectID = cno.ID;
                        EntityTools.FillSystemFiledForAdd(ele, cdo);
                    }
                }
                //处理CNO关联的所属CDOID
                if (cno.Associations != null && cno.Associations.Count > 0)
                {
                    foreach (var asso in cno.Associations)
                    {
                        EntityTools.FillSystemFiledForAdd(asso, cdo);
                        asso.CompositeDataObjectID = cdo.ID;
                        asso.CompositeNodeObjectID = cno.ID;
                        asso.AssoCompositeDataObjectID = cdo.ID;
                        if (asso.Items != null && asso.Items.Count > 0)
                        {
                            foreach (var item in asso.Items)
                            {
                                item.AssociationID = asso.ID;
                                item.CompositeDataObjectID = cdo.ID;
                                EntityTools.FillSystemFiledForAdd(item, cdo);
                            }
                        }
                        if (asso.RefElements != null && asso.RefElements.Count > 0)
                        {
                            foreach (var @ref in asso.RefElements)
                            {
                                @ref.AssociationID = asso.ID;
                                @ref.CompositeDataObjectID = cdo.ID;
                                EntityTools.FillSystemFiledForAdd(@ref, cdo);
                            }
                        }
                    }
                }
                #endregion
            }

            /***********低代码改动：增加CDO保存时设置CNO节点别名Alias的功能*************/
            SetCompositeNodeObjectAlias(cdo);

            try
            {
                using (TransactionScope scope = new TransactionScope(TransactionScopeAsyncFlowOption.Suppress))
                {
                    //保存CDO CNO
                    _compositeDataObjectDao.SaveCompositeDataObject(cdo);
                    //保存CNO.ele
                    var ele = cdo.CompositeNodeObjects.SelectMany(cno => cno.Elements).ToList();
                    _compositeDataObjectDao.SaveCompositeNodeObjectElements(ele);
                    //保存Asso, 单节点情况没有Asso
                    var assoList = cdo.CompositeNodeObjects
                                                      ?.SelectMany(cno => cno.Associations).ToList();
                    if (assoList != null && assoList.Count > 0)
                    {
                        _compositeDataObjectDao.SaveDomainAssociation(assoList);
                        //保存AssoItem
                        _compositeDataObjectDao.SaveDomainAssociationItem(assoList.SelectMany(asso => asso.Items)?.ToList());
                        //保存外键Asso.refele
                        var refList = assoList.SelectMany(asso => asso.RefElements)?.ToList();
                        if (refList != null && refList.Count > 0)
                            _compositeDataObjectDao.SaveAssociationRefElements(assoList.SelectMany(asso => asso.RefElements)?.ToList());
                    }
                    scope.Complete();
                }
            }
            catch (Exception e)
            {
                throw new FasException(DataModelErrorCode.CDO.CreateError, $"{unifyCode}保存失败,Msg:{e.Message}", e);
            }
        }

        public void SaveCompositeNodeObjectElements(List<CompositeNodeObjectElement> elements)
        {
            _compositeDataObjectDao.SaveCompositeNodeObjectElements(elements);
        }

        public void SaveDomainAssociation(List<Association> associations)
        {
            _compositeDataObjectDao.SaveDomainAssociation(associations);
        }

        public void SaveDomainAssociationItem(List<AssociateItem> associateItems)
        {
            _compositeDataObjectDao.SaveDomainAssociationItem(associateItems);
        }

        public void SaveAssociationRefElements(List<AssociationRefElement> refElements)
        {
            _compositeDataObjectDao.SaveAssociationRefElements(refElements);
        }

        #endregion

        #region 删除

        /// <summary>
        /// 删除CDO
        /// </summary>
        /// <param name="id"></param>
        public void DeleteCompositeDataObject(string id)
        {
            if (string.IsNullOrEmpty(id)) return;
            try
            {
                using (var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions(){IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted}))
                {
                    DeleteCompositeDataObjectByID(id);
                    scope.Complete();
                }
            }
            catch (Exception e)
            {
                throw new FasException(DataModelErrorCode.CDO.DeleteError, $"{MetaDataName}元数据删除失败,ID:{id},Msg:{e.Message}", e);
            }
        }

        public void DeleteCompositeDataObjects(List<string> idList)
        {
            if (idList == null) return;
            try
            {
                using (var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions(){IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted}))
                {
                    foreach (var id in idList)
                    {
                        DeleteCompositeDataObjectByID(id);
                    }
                    scope.Complete();
                }
            }
            catch (Exception e)
            {
                throw new FasException(DataModelErrorCode.CDO.DeleteError, $"{MetaDataName}元数据删除失败,Msg:{e.Message}", e);
            }
        }

        private void DeleteCompositeDataObjectByID(string id)
        {
            _compositeDataObjectDao.DeleteCompositeDataObject(id);
            _compositeNodeObjectELBDao.DeleteByMetaDataForeignKey(id);
            _elementELBDao.DeleteByMetaDataForeignKey(id);
            _associationELBDao.DeleteByMetaDataForeignKey(id);
            _associateItemELBDao.DeleteByMetaDataForeignKey(id);
            _associationRefElementELBDao.DeleteByMetaDataForeignKey(id);
        }
        #endregion

        #region 修改
        /// <summary>
        /// 修改元数据 ****CNO.ID必须跟新增时保持一致
        /// </summary>
        /// <param name="metaData"></param>
        public void Update(CompositeDataObject metaData)
        {
            var unifyCode = DataModelErrorCode.GetUnifiedErrorCode(MetaDataID, metaData?.ID, metaData?.Code);
            try
            {
                using (var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions(){IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted}))
                {
                    this.DeleteCompositeDataObject(metaData.ID);
                    this.SaveCompositeDataObject(metaData);
                    scope.Complete();
                }
            }
            catch (Exception e)
            {
                throw new FasException(DataModelErrorCode.CDO.UpdateError, $"{unifyCode}修改失败!Msg:{e.Message}", e);
            }
        }

        #endregion

        #region 修复
        /// <summary>
        /// 修复CDO，修复场景，针对CNO
        /// 1、DataObject删除列
        /// 2、DataObject修改列名，在Repair方法中搞
        /// 3、DataObject修改列的类型改为特殊类型（DO SDO)
        /// </summary>
        /// <param name="cdoID"></param>
        public void Repair(string cdoID)
        {
            var cdo = this.GetCompositeDataObject(cdoID);
            if (cdo == null)
                throw new FasException(DataModelErrorCode.CDO.RetrieveError, $"获取CDO:{cdoID}失败,未在数据库中找到CDO的实例");
            var unifyCode = DataModelErrorCode.GetUnifiedErrorCode(cdoID, cdo?.ID, cdo?.Code);
            try
            {
                List<CompositeNodeObjectElement> dropElements = new List<CompositeNodeObjectElement>();
                foreach (var cno in cdo.CompositeNodeObjects)
                {
                    //场景1、DataObject删除列，关联删掉CDO中的element元素
                    var dropEles = cno.Elements.Where(e => e.ElementType == ElementType.Normal && e.DataColumn == null).ToList();
                    if (dropEles != null && dropEles.Count > 0)
                    {
                        dropElements.AddRange(dropEles);
                        cno.Elements.RemoveAll(e => e.ElementType == ElementType.Normal && e.DataColumn == null);
                    }

                    ////获取外键展示列集合
                    //var outAssoEle = cno.Elements.Where(e => e.ElementType == ElementType.Reference).ToList();
                    ////获取
                    //var outAssoItemTargetElements = cno.Associations
                    //                .Where(asso => asso.AssociateType == AssociateType.OuterLeftJoin)
                    //                ?.Select(asso => asso.Items.FirstOrDefault())
                    //                ?.Select(item => item.TargetElementID)
                    //                ?.ToList();
                    //if (outAssoEle.Count > 0)
                    //{
                    //    var needDropOutAssoEle = outAssoEle.Where(outEle => outAssoItemTargetElements == null
                    //                                                        || outAssoItemTargetElements.Count == 0
                    //                                                        || !outAssoItemTargetElements.Contains(outEle.ID)).ToList();
                    //    if (needDropOutAssoEle != null && needDropOutAssoEle.Count > 0)
                    //    {
                    //        dropElements.AddRange(needDropOutAssoEle);
                    //        foreach (var item in needDropOutAssoEle)
                    //        {
                    //            cno.Elements.Remove(item);
                    //        }
                    //    }
                    //}
                }

                var dropElementIDs = dropElements.Select(ele => ele.ID)?.ToList();
                if (dropElementIDs != null && dropElementIDs.Count > 0)
                    _elementELBDao.Delete(dropElementIDs);

                //场景3、DataObject修改列的类型改为特殊类型（DO SDO)
                CompositeDataObjectValidator compositeDataObjectValidator = new CompositeDataObjectValidator();
                compositeDataObjectValidator.Repair(cdo);
            }
            catch (Exception e)
            {
                throw new FasException(DataModelErrorCode.CDO.RepairError, $"{unifyCode}修复失败, Msg:{e.Message}", e);
            }
        }
        #endregion

        #region Private Funcs
        public CompositeDataObject SetCompositeNodeObjectAlias(CompositeDataObject cdo)
        {
            if (cdo == null)
                return null;
            string errmsg = string.Empty;
            foreach (var cno in cdo.CompositeNodeObjects)
            {
                //CDO不需要处理导入导出的元数据依赖，因为DO导入在CDO之前
                if (cno.DataObject == null || string.IsNullOrEmpty(cno.DataObject.Code))
                    cno.DataObject = _dataObjectDao.GetDataObjectByID(cno.DataObjectID);
                if (cno.DataObject == null)
                    errmsg += $"cno:{cno.ID}的dataobject:{cno.DataObjectID}不存在！\r\n";
            }
            if (!string.IsNullOrEmpty(errmsg))
                throw new FasException(DataModelErrorCode.CDO.GenerateCNOAliasError, $"CDO生成DO别名失败！{errmsg}");
            var group = cdo.CompositeNodeObjects.GroupBy(cno => cno.DataObject.ID);
            foreach (var item in group)
            {
                var cnoList = item.ToList();
                var alias = cnoList.First().DataObject.Code;
                for (int i = 0; i < cnoList.Count; i++)
                {
                    cnoList[i].DataObjectTableAlias = alias + (i == 0 ? "" : i.ToString());
                }
            }
            /******低代码改动:将所有外键关联Asso设置关联DataObject的别名Alias******/
            Dictionary<string, int> outerJoinTableAlias = new Dictionary<string, int>();
            foreach (var cno in cdo.CompositeNodeObjects)
            { 
                var leftAsso = cno.Associations?.Where(asso => asso.AssociateType == AssociateType.OuterLeftJoin);
                if (leftAsso != null && leftAsso.Count() > 0)
                {
                    foreach (var asso in leftAsso)
                    {
                        if (asso.AssoDataObject == null || string.IsNullOrEmpty(asso.AssoDataObject.Code))
                            asso.AssoDataObject = _dataObjectDao.GetDataObjectByID(asso.AssoDataObjectID);
                        var leftJoinDOCode = asso.AssoDataObject.Code;
                        if (!outerJoinTableAlias.ContainsKey(leftJoinDOCode))
                        {
                            outerJoinTableAlias[leftJoinDOCode] = 0;
                        }
                        else
                        {
                            outerJoinTableAlias[leftJoinDOCode]++;
                        }
                        asso.AssoDataObjectTableAlias = "LeftJoin" + leftJoinDOCode + outerJoinTableAlias[leftJoinDOCode];
                    }
                }
            }
            return cdo;
        }
        #endregion
    }
}
